package org.kernely.stream.userpage;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.kernely.security.dao.UserDetailsDAO;
import org.kernely.security.persistence.Role;
import org.kernely.security.persistence.User;
import org.kernely.security.persistence.UserDetails;
import org.kernely.stream.StreamBundle;
import org.kernely.stream.dao.MessageDAO;
import org.kernely.stream.dao.StreamDAO;
import org.kernely.stream.persistence.Message;
import org.kernely.stream.persistence.Stream;
import org.kernely.stream.utils.FavButton;
import org.kernely.stream.utils.MessageComparator;
import org.kernely.ui.mvp.KernelyEvent;
import org.kernely.ui.mvp.KernelyEventReceiver;
import org.kernely.ui.mvp.KernelyPresenter;
import org.kernely.ui.utils.DisplayProfileEvent;
import org.kernely.ui.utils.KernelyDialogWindow;
import org.kernely.ui.utils.KernelyNotification;

import com.vaadin.data.Property;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.event.FieldEvents.TextChangeEvent;
import com.vaadin.event.FieldEvents.TextChangeListener;
import com.vaadin.terminal.ExternalResource;
import com.vaadin.terminal.FileResource;
import com.vaadin.terminal.Sizeable;
import com.vaadin.terminal.ThemeResource;
import com.vaadin.ui.Button;
import com.vaadin.ui.Embedded;
import com.vaadin.ui.Label;
import com.vaadin.ui.Layout;
import com.vaadin.ui.Table;
import com.vaadin.ui.Window;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.themes.Reindeer;

/**
 * The Presenter which fill the StreamMessagesView.
 */
@SuppressWarnings("serial")
public class StreamMessagesPresenter extends KernelyPresenter<StreamMessagesView> implements KernelyEventReceiver {

	private Integer oldestDisplayedMessage = -1;
	private Integer newestLoadedMessage = -1;
	private Integer previous = 1;
	private int nbMessagesDisplayed = 7;
	private Thread oldthread = new Thread(new OldMessageLoaderRunnable());
	private Thread poolThread = new Thread(new NewMessageLoaderRunnable());
	private Stream filter = null;

	/**
	 * Fill the UserPageView with data.
	 */
	@Override
	public final void bind() {

		// Registering as an event receiver to be called by StreamUserPageAttachedEvent
		StreamBundle.getEventBus().addListener(this);

		this.view.getStreamSettingsButton().addListener(new ClickListener(){
			/**
			 * Action called when the button is clicked.
			 */
			public void buttonClick (Button.ClickEvent event) {
				displayStreamSettingsWindow();
			}
		});

		poolThread.start();

		this.view.getLengthLabel().setValue("Remain : " + Message.MESSAGE_LENGTH);

		this.view.getInputMessage().addListener(new TextChangeListener() {

			/**
			 * @see com.vaadin.event.FieldEvents.TextChangeListener#textChange(com.vaadin.event.FieldEvents.TextChangeEvent)
			 */
			public void textChange(TextChangeEvent event) {
				int inputLength = Message.MESSAGE_LENGTH - event.getText().length();
				view.getLengthLabel().setValue("Remain : " + inputLength);
				if(inputLength < 0 || inputLength >= Message.MESSAGE_LENGTH){
					view.getPostButton().setEnabled(false);
					if(inputLength <= 0){
						view.getInfoLabel().setValue("<span style=\"color:red;\">Your message is too long.</span>");
					}
					if(inputLength >= Message.MESSAGE_LENGTH){
						view.getInfoLabel().setValue("<span style=\"color:red;\">You have to enter a message.</span>");
					}
				}
				else{
					if(!view.getPostButton().isEnabled() && inputLength >= 0 && inputLength < Message.MESSAGE_LENGTH){
						view.getPostButton().setEnabled(true);
						view.getInfoLabel().setValue("");
					}
				}

			}
		});

		this.view.getLengthCommentLabel().setValue("Remain : " + Message.MESSAGE_LENGTH);

		this.view.getInputComment().addListener(new TextChangeListener() {
			/**
			 * @see com.vaadin.event.FieldEvents.TextChangeListener#textChange(com.vaadin.event.FieldEvents.TextChangeEvent)
			 */
			public void textChange(TextChangeEvent event) {
				int inputLength = Message.MESSAGE_LENGTH - event.getText().length();
				view.getLengthCommentLabel().setValue("Remain : " + inputLength);
				if(inputLength < 0 || inputLength >= Message.MESSAGE_LENGTH){
					view.getPostCommentButton().setEnabled(false);
					if(inputLength <= 0){
						view.getInfoCommentLabel().setValue("<span style=\"color:red;\">Your message is too long.</span>");
					}
					if(inputLength >= Message.MESSAGE_LENGTH){
						view.getInfoCommentLabel().setValue("<span style=\"color:red;\">You have to enter a message.</span>");
					}
				}
				else{
					if(!view.getPostCommentButton().isEnabled() && inputLength >= 0 && inputLength < Message.MESSAGE_LENGTH){
						view.getPostCommentButton().setEnabled(true);
						view.getInfoCommentLabel().setValue("");
					}
				}

			}
		});

		this.view.getStreamSearchText().addListener(new TextChangeListener() {
			/**
			 * @see com.vaadin.event.FieldEvents.TextChangeListener#textChange(com.vaadin.event.FieldEvents.TextChangeEvent)
			 */
			public void textChange(TextChangeEvent event) {
				if(event.getText().length() != 0){
					if(event.getText().length() > 2){
						view.getMessageTable().removeAllItems();

						TreeSet<Message> ordered = new TreeSet<Message>(new MessageComparator());
						MessageDAO mdao = MessageDAO.getInstance();
						User current = StreamBundle.getSecurityService().getCurrentUser();

						ordered.addAll(mdao.getSearchMessages(current, event.getText()));
						Message buffer;
						for (final Message message : ordered){
							buffer = new Message();
							String txt2Highlight = message.getContent();
							String regexp = "(" + event.getText() + ")";

							Pattern p = Pattern.compile(regexp, Pattern.CASE_INSENSITIVE);
							Matcher m = p.matcher(txt2Highlight);
							StringBuffer sb = new StringBuffer();
							while (m.find()) {
								m.appendReplacement(sb, "<span style=\"background-color:#9DE8F7;\">" + m.group(1) + "</span>");
							}
							m.appendTail(sb);

							buffer.setId(message.getId());
							buffer.setContent(message.getContent());
							buffer.setDate(message.getDate());
							buffer.setStream(message.getStream());
							buffer.setComments(message.getComments());
							buffer.setCommentable(message.getCommentable());
							buffer.setFavoriteUsers(message.getFavoriteUsers());
							buffer.setMessage(message.getMessage());
							buffer.setUser(message.getUser());
							buffer.setContentCache(StreamBundle.getStreamService().applyStreamFilters(sb.toString()));
							addMessageIntoTable(buffer, false);

						}
					}
				}
				else{
					oldestDisplayedMessage = -1;
					listMessages();
				}
			}
		});

		this.view.getStreamSearchText().addListener(new Property.ValueChangeListener() {
			/**
			 * @see com.vaadin.data.Property.ValueChangeListener#valueChange(com.vaadin.data.Property.ValueChangeEvent)
			 */
			public void valueChange(ValueChangeEvent event) {
				if(view.getStreamSearchText().getValue().toString().length() == 0){
					oldestDisplayedMessage = -1;
					listMessages();
				}
			}
		});

		this.view.getPostButton().addListener(new ClickListener(){
			/**
			 * @see com.vaadin.ui.Button.ClickListener#buttonClick(com.vaadin.ui.Button.ClickEvent)
			 */
			public void buttonClick (Button.ClickEvent event) {
				postMessage();
			}
		});

		this.view.getPostCommentButton().addListener(new ClickListener(){
			/**
			 * @see com.vaadin.ui.Button.ClickListener#buttonClick(com.vaadin.ui.Button.ClickEvent)
			 */
			public void buttonClick (Button.ClickEvent event) {
				postComment();
			}
		});

		this.view.getMoreResults().addListener(new ClickListener() {
			/**
			 * @see com.vaadin.ui.Button.ClickListener#buttonClick(com.vaadin.ui.Button.ClickEvent)
			 */
			public void buttonClick(ClickEvent event) {
				if(!oldthread.isAlive()){
					oldthread.run();
				}
			}
		});

		// Fill the streams combo box with all the available streams
		// (i.e. streams where the user can post (write permission, and post not locked)
		for (Stream stream : StreamDAO.getInstance().getAllStream()){
			//A user can only write on some streams (or all if he is administrator)
			boolean isAdmin = StreamBundle.getSecurityService().currentUserHasOneOf(Role.ROLE_ADMINISTRATOR);
			boolean hasRights = StreamBundle.getSecurityService().currentUserHasPermission(stream.getCategory()+":write:"+stream.getUid());
			boolean locked = stream.getLocked() == 1;
			if ((isAdmin || hasRights) && ! locked){
				//Add the stream
				this.view.getStreamsBox().addItem(stream);
				this.view.getStreamsBox().setItemCaption(stream, stream.getTitle());
			}
		}
		String currentUserLogin = StreamBundle.getSecurityService().getCurrentUser().getLogin();
		Stream userStream = StreamDAO.getInstance().findStream(Stream.CATEGORY_USERS, currentUserLogin);

		// Set the stream to the user's stream
		this.view.getStreamsBox().setValue(userStream);


		// Fill the streams filter combo box with all the suscribed streams
		// TODO IMPROVE
		this.updateFilter();

		// Add a listener to the filter combobox to update or disable the post panel in function of stream selected
		this.view.getStreamFilterBox().addListener(new Property.ValueChangeListener() {
			/**
			 * @see com.vaadin.data.Property.ValueChangeListener#valueChange(com.vaadin.data.Property.ValueChangeEvent)
			 */
			public void valueChange(ValueChangeEvent event) {
				oldestDisplayedMessage = -1;
				if(view.getStreamFilterBox().getValue() instanceof Stream){
					// retrieve the stream selected
					filter = (Stream)view.getStreamFilterBox().getValue();
					// If the user can write on the selected stream, we force writing on it, panel is disabled otherwise
					if(view.getStreamsBox().containsId(filter)){
						view.getStreamsBox().setValue(filter);
						view.getStreamsBox().setEnabled(false);
						view.getPostPanel().setEnabled(true);
					}
					else{
						view.getPostPanel().setEnabled(false);
					}
				}
				else{
					if(!view.getPostPanel().isEnabled()){
						view.getPostPanel().setEnabled(true);
					}
					if(!view.getStreamsBox().isEnabled()){
						view.getStreamsBox().setEnabled(true);
					}
					filter = null;
				}
				listMessages();
			}
		});



		// Add a listener to the table
		this.view.getMessageTable().addListener(new Property.ValueChangeListener() {
			/**
			 * @see com.vaadin.data.Property.ValueChangeListener#valueChange(com.vaadin.data.Property.ValueChangeEvent)
			 */
			public void valueChange(ValueChangeEvent event) {
				Integer id = (Integer)view.getMessageTable().getValue();
				if(id == null){
					hideMessageDetails();
				}
				else{
					Message message = MessageDAO.getInstance().findMessageById((Integer)view.getMessageTable().getValue());
					if(message.getCommentable() == 1){
						displayMessageDetails(message);
					}
					else{
						hideMessageDetails();
					}
				}

			}
		});

		view.getMessageTable().setCellStyleGenerator(new Table.CellStyleGenerator() {
			/**
			 * @see com.vaadin.ui.Table.CellStyleGenerator#getStyle(java.lang.Object, java.lang.Object)
			 */
			public String getStyle(Object itemId, Object propertyId) {
				Message message = MessageDAO.getInstance().findMessageById((Integer)itemId);
				if(message.getComments() != null && message.getComments().size() > 0){
					if(MessageDAO.getInstance().getFavorites(StreamBundle.getSecurityService().getCurrentUser()).contains(message)){
						return "favcomments";
					}
					else{
						return "comments";
					}
				}
				else{
					if(MessageDAO.getInstance().getFavorites(StreamBundle.getSecurityService().getCurrentUser()).contains(message)){
						return "favorites";
					}
					else{
						return "messages";
					}
				}
			}
		});

	}

	/**
	 * Update the combobox which allows to select a filter on displayed stream
	 */
	private void updateFilter(){
		this.view.getStreamFilterBox().removeAllItems();
		this.view.getStreamFilterBox().addItem(0);
		this.view.getStreamFilterBox().setItemCaption(0, "All streams");
		for (Stream stream : StreamDAO.getInstance().getUserSubscribedStream(StreamBundle.getSecurityService().getCurrentUser())){
			this.view.getStreamFilterBox().addItem(stream);
			this.view.getStreamFilterBox().setItemCaption(stream, stream.getTitle());
		}

		// By default, select all streams displayed
		view.getStreamFilterBox().setValue(0);
	}

	/**
	 * Save a message posted by the user
	 */
	private void postMessage(){
		String content = this.view.getInputMessage().getValue().toString();

		if (content != null && content != "" ){
			Message newMessage = new Message();
			newMessage.setContent(content);
			// Write on user's stream
			newMessage.setUser(StreamBundle.getSecurityService().getCurrentUser());
			java.sql.Date date = new java.sql.Date(new Date().getTime());
			newMessage.setDate(date);

			Stream stream = (Stream) this.view.getStreamsBox().getValue();
			newMessage.setStream(stream);

			if((Boolean)view.getCommentableMessage().getValue()){
				newMessage.setCommentable(1);
			}
			else{
				newMessage.setCommentable(0);
			}

			// Check if the stream is unlocked
			if (stream.getLocked() == 0){
				// Prevent NullPointer
				newMessage.setFavoriteUsers(new HashSet<User>());
				newMessage.setContentCache(StreamBundle.getStreamService().applyStreamFilters(content));
				MessageDAO.getInstance().saveMessage(newMessage);

				this.view.getInputMessage().setValue("");
				this.view.getInputMessage().focus();
				this.view.getLengthLabel().setValue("Remain : " + Message.MESSAGE_LENGTH);
			} else {
				view.getWindow().showNotification(new KernelyNotification("You can't post on this stream because it is locked.", KernelyNotification.ERROR_ICON));
			}
			loadNewMessages(true);
		}
	}

	/**
	 * Save a comment posted by the user
	 */
	private void postComment(){
		String content = this.view.getInputComment().getValue().toString();
		int messageId = Integer.valueOf(view.getMessageDisplayed().toString());
		Message messageParent = MessageDAO.getInstance().findMessageById(messageId);
		if(messageParent.getCommentable() == 1){
			if (content != null && content != "" ){
				Message newComment = new Message();
				newComment.setContent(content);
				// Write on user's stream
				newComment.setUser(StreamBundle.getSecurityService().getCurrentUser());
				java.sql.Date date = new java.sql.Date(new Date().getTime());
				newComment.setDate(date);



				newComment.setMessage(messageParent);
				newComment.setStream(messageParent.getStream());
				newComment.setContentCache(StreamBundle.getStreamService().applyStreamFilters(content));
				MessageDAO.getInstance().saveMessage(newComment);
				this.view.getInputComment().setValue("");
				this.view.getInputComment().focus();
				loadComments(messageParent);
				this.view.getLengthCommentLabel().setValue("Remain : " + Message.MESSAGE_LENGTH);
			}
		}
	}

	/**
	 * Display the pop up window which allows to select subscribed streams
	 */
	private void displayStreamSettingsWindow(){
		StreamSettingsWindowPresenter presenter  = new StreamSettingsWindowPresenter();
		StreamSettingsWindowView view = new StreamSettingsWindowView();
		presenter.setView(view);

		Window subwindow = new Window("Kernely - Edit stream settings");
		subwindow.setModal(true);
		subwindow.setResizable(false);
		this.view.getWindow().addWindow(subwindow);
		subwindow.getContent().setSizeUndefined();

		subwindow.setContent((Layout)presenter.getView());
		subwindow.setIcon(new ExternalResource("/streambundle/images/custom.png"));
	}


	/**
	 * Display messages, only when the view has been attached, to get Application reference.
	 */
	public final void handleKernelyEvent(KernelyEvent event) {
		if (event instanceof StreamMustDisplayMessagesEvent){
			updateFilter();
			oldestDisplayedMessage = -1; // To force the removal and then the display of all messages.
			if(!oldthread.isAlive()){
				oldthread.run();
			}
		}
	}	

	/**
	 * Actualize the displayed messages (add new messages, don't reload all messages).
	 */
	private synchronized void listMessages(){
		TreeSet<Message> ordered = new TreeSet<Message>(new MessageComparator());
		User current = StreamBundle.getSecurityService().getCurrentUser();
		if (oldestDisplayedMessage == -1){
			// Remove all the streams.
			view.getMessageTable().removeAllItems();
			Set<Message> set = MessageDAO.getInstance().getUserMessages(current, 0, nbMessagesDisplayed, filter);
			ordered.addAll(set);
			if(!ordered.isEmpty()){
				newestLoadedMessage = ordered.last().getId();
				if(ordered.size()>1){
					previous = ordered.lower(ordered.last()).getId();
				}
			}
		}
		else{
			ordered.addAll(MessageDAO.getInstance().getNextMessages(current, MessageDAO.getInstance().findMessageById(oldestDisplayedMessage), nbMessagesDisplayed, filter));
		}
		if(ordered.isEmpty()){
			return;
		}
		oldestDisplayedMessage = ordered.first().getId();

		// Display all messages
		for (final Message message : ordered){
			addMessageIntoTable(message, false);
		}
		view.getMessageTable().sort();
	}

	/**
	 * Runnable called by the thread charged to display older messages
	 */
	public final class OldMessageLoaderRunnable implements Runnable {
		/**
		 * @see java.lang.Runnable#run()
		 */
		public void run() {
			listMessages();
		}
	}

	/**
	 * Runnable called by the thread charged to refresh and display all new messages
	 */
	public final class NewMessageLoaderRunnable implements Runnable {
		
		private boolean stopThread = false;

		/**
		 * @see java.lang.Runnable#run()
		 */
		public void run() {
	        boolean end = false;
			while(! end){
				try {
					Thread.sleep(5000);
					loadNewMessages(false);
					
					synchronized(this) {
                        Thread.yield();
                        
                        // lecture du boolean 
                        end = this.stopThread;
					}					
				} catch (InterruptedException e) {
					// TODO CHANGE STACKTRACE
					e.printStackTrace();
				}
			}
		}

		public synchronized void stop() {
		        this.stopThread = true;
		} 

		
	}

	/**
	 * Called every 5 seconds to display all new messages
	 * @param fromPostMessage : true if this method call was forced, false otherwise
	 */
	public final synchronized void loadNewMessages(boolean fromPostMessage){
		if(newestLoadedMessage != -1 || fromPostMessage){
			TreeSet<Message> ordered = new TreeSet<Message>(new MessageComparator());
			MessageDAO mdao = MessageDAO.getInstance();
			User current = StreamBundle.getSecurityService().getCurrentUser();
			if (current == null){
				// The user is no more connnected.
				oldthread.interrupt();
				
				//TODO improve: stop the thread when user quit the page,
				// not only when he logout
				poolThread.stop();
			} else {
				// Get recents messages
				Set<Message> set = mdao.getAllRecentMessage(current, mdao.findMessageById(newestLoadedMessage), filter);
				ordered.addAll(set);

				if(ordered.isEmpty()){
					return;
				}
				newestLoadedMessage = ordered.last().getId();
				if(ordered.size()>1){
					previous = ordered.lower(ordered.last()).getId();
				}
				// Display all messages
				for (final Message message : ordered){
					addMessageIntoTable(message, false);
				}
				view.getMessageTable().sort();

			}
		}
	}

	/**
	 * Display the panel containing message's details and comments
	 * @param message : message to display
	 */
	public final void displayMessageDetails(Message message){
		view.getDetailsLayout().setVisible(true);
		// Writer infos
		view.getMessageDisplayed().setValue(message.getId());
		view.getPostCommentPanel().setEnabled(true);
		UserDetails details = UserDetailsDAO.getInstance().getUserDetails(message.getUser());

		//Date
		SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");
		SimpleDateFormat dateHourFormat = new SimpleDateFormat("kk:mm:ss");

		String user = null;
		if (details != null){
			user = details.getFirstname() + " " + details.getName() + " (" + details.getUser().getLogin() + ")";
		} else {
			user = "System";
		}

		view.getStreamName().setValue(message.getStream().getTitle());
		view.getMessageContent().setValue(
				"<br/><span style=\"font-style:italic;color:grey\">From "+user+", the "+dateFormat.format(message.getDate())+" at "+dateHourFormat.format(message.getDate())+" :</span>"
				+ "<br/>" +  message.getContentCache());
		// Loads message's comments
		loadComments(message);
	}

	/**
	 * Hide the panel containing message's details and comments
	 */
	public final void hideMessageDetails(){
		view.getDetailsLayout().setVisible(false);
		//view.getMessageDisplayed().setValue(null);
		view.getPostCommentPanel().setEnabled(false);
	}

	/**
	 * Loads all comments relative to this message
	 * @param message : the message concerned
	 */
	public final void loadComments(Message message){
		view.getCommentTable().removeAllItems();
		TreeSet<Message> ordered = new TreeSet<Message>(new MessageComparator());
		ordered.addAll(MessageDAO.getInstance().getAllCommentsFromMessage(message));
		for(Message c : ordered){
			addMessageIntoTable(c, true);
		}
	}

	public final void addMessageIntoTable(final Message message, boolean isComment){
		// Writer infos
		final UserDetails details = UserDetailsDAO.getInstance().getUserDetails(message.getUser());

		//Date
		SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");

		String user = null;
		if (details != null){
			user = details.getFirstname() + " " + details.getName() + " (" + details.getUser().getLogin() + ")";
		} else {
			user = "System";
		}

		Date messageDate = message.getDate();
		Calendar date1 = new GregorianCalendar();
		date1.setTime(messageDate);
		Calendar date2 = new GregorianCalendar();
		long date1long = date1.getTimeInMillis();
		long date2long = date2.getTimeInMillis();

		// Difference between the two dates
		long timebetweend1d2 = date2long - date1long;
		String dateToDisplay = "";
		// less than one minute
		if(timebetweend1d2 < 60000){
			dateToDisplay = "a few seconds ago";
		}
		else{
			// less than one hour
			if(timebetweend1d2 < 3600000){
				long nbMin = timebetweend1d2 / 1000 / 60;
				dateToDisplay = nbMin + " minutes ago";
			}
			else{
				// less than one day
				if(timebetweend1d2 < 86400000){
					long nbHour = timebetweend1d2 / 1000 / 60 / 60;
					dateToDisplay = nbHour + " hours ago";
				}
				else{
					// less than one week
					if(timebetweend1d2 < 604800000){
						long nbDays = timebetweend1d2 / 1000 / 60 / 60 / 24;
						dateToDisplay = nbDays + " days ago";
					}
					else{
						dateToDisplay = dateFormat.format(messageDate);
					}
				}
			}
		}

		// Format the text to be displayed in the table
		Label messageContent;
		if(!isComment){
			messageContent = new Label(
					"<span style=\"font-weight:bold;\">"+message.getStream().getTitle()+"</span><br/>"
					+ message.getContentCache()+"<br/>"
					+"<span style=\"font-style:italic;color:grey\">From "+user + ", " + dateToDisplay + ".</span>",Label.CONTENT_XHTML);
		}
		else{
			messageContent = new Label(
					"<span style=\"font-style:italic;color:grey\">From "+user+", "+ dateToDisplay +" :</span><br/>"
					+ message.getContentCache(),Label.CONTENT_XHTML);
		}

		// Set the image
		Embedded imageEmbedded = new Embedded();
		// The image for "system" user is a default image
		if (details == null){
			ThemeResource imageResource = new ThemeResource("img/default_bundle.png");
			imageEmbedded.setSource(imageResource);
		}
		else {
			if (details.getImage() == null || details.getImage().equals("")){
				// Default images are located in src/main/resources/VAADIN/themes/kernelytheme/img
				if (details.getCivility() == 0){
					ThemeResource imageResource = new ThemeResource("img/default_male.png");
					imageEmbedded.setSource(imageResource);
				}
				else {
					ThemeResource imageResource = new ThemeResource("img/default_female.png");
					imageEmbedded.setSource(imageResource);
				}
			} else {
				File imageFile = new File("/tmp/uploads/"+details.getImage());
				if (imageFile != null){
					// We set the image only if the application is available
					if (view.getApplication() != null){
						FileResource imageResource = new FileResource(imageFile, view.getApplication());
						imageEmbedded.setSource(imageResource);	        	
					}
				}
			}        
		}
		imageEmbedded.setHeight(48, Sizeable.UNITS_PIXELS);
		imageEmbedded.setWidth(48, Sizeable.UNITS_PIXELS);

		// Delete button, only for users which correct rights
		Button deleteButton = null;
		if (StreamBundle.getSecurityService().currentUserHasOneOf(Role.ROLE_ADMINISTRATOR)
				|| StreamBundle.getSecurityService().currentUserHasPermission(
						message.getStream().getCategory() + ":deletemessages:" + message.getStream().getUid())
						|| message.getUser().equals(StreamBundle.getSecurityService().getCurrentUser())){
			deleteButton = new Button();
			deleteButton.setIcon(new ThemeResource("img/cancel_icon16*16.png"));
			deleteButton.setStyleName(Reindeer.BUTTON_LINK);

			deleteButton.setSizeUndefined();
			deleteButton.addListener(new Button.ClickListener() {
				/**
				 * @see com.vaadin.ui.Button.ClickListener#buttonClick(com.vaadin.ui.Button.ClickEvent)
				 */
				public void buttonClick(ClickEvent event) {
					deleteProcess(message);
				}
			});
		}	

		// creation of profile button
		Button buttonProfile = null;
		if (! user.equals("System")){
			// Display the profile only if the user is not the System
			buttonProfile = new Button();
			buttonProfile.setIcon(new ThemeResource("img/profile.png"));
			buttonProfile.setStyleName(Reindeer.BUTTON_LINK);
			buttonProfile.addListener(new Button.ClickListener() {
				/**
				 * @see com.vaadin.ui.Button.ClickListener#buttonClick(com.vaadin.ui.Button.ClickEvent)
				 */
				public void buttonClick(ClickEvent event) {
					displayProfile(details);
				}
			});
		}

		// Create the message
		if(!isComment){
			this.view.getMessageTable().addItem(new Object[] {
					imageEmbedded,
					messageContent,
					buttonProfile,
					new FavButton(message),
					deleteButton,
					message.getDate()}, message.getId());
		}
		else{
			this.view.getCommentTable().addItem(new Object[] {
					imageEmbedded,
					messageContent,
					buttonProfile,
					deleteButton,
					message.getDate()}, message.getId());

		}
	}

	/**
	 * Display the profile selected
	 * @param details : the profile to display
	 */
	private void displayProfile(UserDetails details){
		StreamBundle.getEventBus().broadcastEvent(new DisplayProfileEvent(this, details));	
	}

	/**
	 * Process to delete a message, with confirm dialog and notification.
	 */
	private void deleteProcess(final Message message){
		boolean isAdmin = StreamBundle.getSecurityService().currentUserHasOneOf(Role.ROLE_ADMINISTRATOR);
		String permission = "Streams/Users:deletemessages:"+message.getStream().getUid();
		boolean canDelete = StreamBundle.getSecurityService().currentUserHasPermission(permission);

		final Window window = view.getWindow();

		// Delete the message if the user have rights.
		if (isAdmin || canDelete){

			// Confirm window
			final KernelyDialogWindow confirm = new KernelyDialogWindow(
					"Kernely - Delete message", "Do you really want to delete this message ?",
					KernelyDialogWindow.ASKING_ICON);
			confirm.setConfirmButtonCaption("Yes");
			confirm.setCancelButtonCaption("No");

			// Adding listeners on window's "confirm" buttons click
			confirm.getConfirmButton().addListener(new Button.ClickListener() {
				/**
				 * The action when the "Yes" button is clicked
				 */
				public void buttonClick(ClickEvent event) {
					MessageDAO mdao = MessageDAO.getInstance();

					/*
					 * If we delete the message saved as the most recent message loaded, loadNewMessage will load all messages in the database.
					 * We update the newestLoadedMessage and the previous message to fix this bug.
					 */
					if(message.getId() == newestLoadedMessage){
						newestLoadedMessage = previous;
					}

					// Disable the user in the database
					mdao.deleteMessage(message);
					window.removeWindow(confirm);

					// Remove the confirm window
					window.showNotification(new KernelyNotification("Message deleted.", KernelyNotification.INFO_ICON));

					view.getMessageTable().removeItem(message.getId());
				}
			});

			window.addWindow(confirm);
		}
	}



	/**
	 * Called when the presenter is no more visible.
	 */
	public final void unset() {
		System.out.println("UNSET");
		StreamBundle.getEventBus().removeListener(this);
	}
}